/*
 建议迁移：
  - 把公用头移动到: d:\test\mytcp\include\net\ (ip.h udp.h tcp.h arp.h)
  - 把驱动头移动到: d:\test\mytcp\include\drivers\ (pcap_adapter.h)
  - 示例代码保留在 d:\test\mytcp\examples\
  - 在构建系统中添加 include/ 到 include 路径
*/

#include "drivers/pcap_adapter.h"
#include "net/ip.h"
#include "net/udp.h"
#include "net/tcp.h"
#include "net/arp.h"

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>

#ifdef _WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#endif

#include <pcap.h> /* for device enumeration */

/* helper: parse MAC string like "001122334455" or "00:11:22:33:44:55" or "00-11-22-33-44-55" */
static int parse_mac(const char* s, uint8_t mac[6]) {
	if (!s || !*s) return -1;
	int vi = 0;
	const char* p = s;
	while (*p && vi < 6) {
		if (*p == ':' || *p == '-' ) { p++; continue; }
		if (!isxdigit((unsigned char)p[0])) return -1;
		int hi = 0;
		/* read two hex chars if available */
		if (isxdigit((unsigned char)p[0]) && isxdigit((unsigned char)p[1])) {
			sscanf(p, "%2x", &hi);
			p += 2;
		} else {
			/* single hex digit (unlikely) */
			sscanf(p, "%1x", &hi);
			p++;
		}
		mac[vi++] = (uint8_t)hi;
		/* skip any separator handled at loop top */
	}
	return vi == 6 ? 0 : -1;
}

static void udp_cb(const uint8_t* payload, size_t len, uint32_t src_ip, uint16_t src_port, void* ctx) {
	(void)ctx;
	printf("UDP recv from %u.%u.%u.%u:%u, len=%zu\n",
		(src_ip>>24)&0xFF,(src_ip>>16)&0xFF,(src_ip>>8)&0xFF,src_ip&0xFF, src_port, len);
}

/* Rename callback to avoid conflict with typedef name in pcap header */
static void on_pcap_recv(const uint8_t* pkt, size_t len, void* ctx) {
	(void)ctx;
	ip_input(pkt, len);
}

int main(int argc, char** argv) {
	// Interactive buffers
	char dev_buf[256] = {0};
	char src_ip_buf[64] = {0};
	char src_mac_buf[64] = {0};
	char dst_ip_buf[64] = {0};
	char dst_mac_buf[64] = {0};

	const char* dev = NULL;
	const char* src_ip_str = NULL;
	const char* src_mac_str = NULL;
	const char* dst_ip_str = NULL;
	const char* dst_mac_str = NULL;

	/* If user provided full args, use them; otherwise enter interactive selection
	   Usage: demo <pcap_device> <src_ip> <src_mac(hex6)> <dst_ip> [dst_mac(hex6)]
	*/
	if (argc >= 5) {
		dev = argv[1];
		src_ip_str = argv[2];
		src_mac_str = argv[3];
		dst_ip_str = argv[4];
		if (argc >= 6) dst_mac_str = argv[5];
	} else {
		/* enumerate devices and ask user to pick */
		pcap_if_t* alldevs;
		char errbuf[PCAP_ERRBUF_SIZE] = {0};
		if (pcap_findalldevs(&alldevs, errbuf) == -1) {
			fprintf(stderr, "pcap_findalldevs failed: %s\n", errbuf);
			return 1;
		}
		printf("Available network devices:\n");
		int idx = 0;
		for (pcap_if_t* d = alldevs; d; d = d->next, ++idx) {
			printf("  [%d] %s", idx, d->name ? d->name : "(no name)");
			if (d->description) printf(" : %s", d->description);
			printf("\n");
		}
		/* prompt for device selection */
		printf("Enter device number or name (default first device): ");
		if (!fgets(dev_buf, sizeof(dev_buf), stdin)) {
			pcap_freealldevs(alldevs);
			return 1;
		}
		dev_buf[strcspn(dev_buf, "\r\n")] = 0;
		int choice = -1;
		if (sscanf(dev_buf, "%d", &choice) == 1 && choice >= 0) {
			int i = 0;
			pcap_if_t* sel = NULL;
			for (pcap_if_t* d = alldevs; d; d = d->next, ++i) {
				if (i == choice) { sel = d; break; }
			}
			if (!sel) {
				fprintf(stderr, "Invalid device index\n");
				pcap_freealldevs(alldevs);
				return 1;
			}
			strncpy(dev_buf, sel->name, sizeof(dev_buf)-1);
			dev_buf[sizeof(dev_buf)-1] = 0;
		} else {
			/* if empty, pick first device name */
			if (dev_buf[0] == '\0' && alldevs) {
				strncpy(dev_buf, alldevs->name, sizeof(dev_buf)-1);
				dev_buf[sizeof(dev_buf)-1] = 0;
			}
		}
		/* free list now */
		pcap_freealldevs(alldevs);
		dev = dev_buf;

		/* prompt for remaining parameters with defaults */
		printf("Enter source IP (default 192.168.0.100): ");
		if (!fgets(src_ip_buf, sizeof(src_ip_buf), stdin)) return 1;
		src_ip_buf[strcspn(src_ip_buf, "\r\n")] = 0;
		if (src_ip_buf[0] == '\0') strcpy(src_ip_buf, "192.168.0.100");
		src_ip_str = src_ip_buf;

		printf("Enter source MAC (hex6, e.g. 001122334455). Leave empty to auto-generate: ");
		if (!fgets(src_mac_buf, sizeof(src_mac_buf), stdin)) return 1;
		src_mac_buf[strcspn(src_mac_buf, "\r\n")] = 0;
		if (src_mac_buf[0] != '\0') src_mac_str = src_mac_buf;
		else src_mac_str = NULL;

		printf("Enter destination IP (default 192.168.0.1): ");
		if (!fgets(dst_ip_buf, sizeof(dst_ip_buf), stdin)) return 1;
		dst_ip_buf[strcspn(dst_ip_buf, "\r\n")] = 0;
		if (dst_ip_buf[0] == '\0') strcpy(dst_ip_buf, "192.168.0.1");
		dst_ip_str = dst_ip_buf;

		printf("Enter destination MAC (hex6). Leave empty to use broadcast FF:FF:FF:FF:FF:FF: ");
		if (!fgets(dst_mac_buf, sizeof(dst_mac_buf), stdin)) return 1;
		dst_mac_buf[strcspn(dst_mac_buf, "\r\n")] = 0;
		if (dst_mac_buf[0] != '\0') dst_mac_str = dst_mac_buf;
	}

	void* handle = NULL;
	if (pcap_adapter_open(dev, &handle) != 0) {
		printf("pcap open failed\n"); return 1;
	}

	/* parse and prepare src_ip/dst_ip and macs */
	uint32_t src_ip = 0;
	{
#ifdef _WIN32
		unsigned long net = src_ip_str ? inet_addr(src_ip_str) : INADDR_NONE;
#else
		in_addr_t net = src_ip_str ? inet_addr(src_ip_str) : INADDR_NONE;
#endif
		if (net == INADDR_NONE) {
			src_ip = (192<<24)|(168<<16)|(0<<8)|100; /* default host-order */
		} else {
			src_ip = ntohl(net); /* store host order */
		}
	}

	uint8_t src_mac[6] = {0};
	if (src_mac_str && parse_mac(src_mac_str, src_mac) == 0) {
		/* ok parsed */
	} else {
		/* leave as zero -> ip_init will auto-generate a local MAC */
		memset(src_mac,0,6);
	}

	ip_init(handle, src_ip, src_mac);
	ip_register_udp_cb(udp_cb, NULL);

	/* destination mac: parse or default broadcast */
	uint8_t dst_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
	if (dst_mac_str && parse_mac(dst_mac_str, dst_mac) != 0) {
		/* parse failed -> keep broadcast */
	}
	/* set forced dst mac in IP layer (will be used for outgoing frames) */
	ip_set_forced_dst_mac(dst_mac);
	ip_set_use_forced_dst_mac(1);

	pcap_adapter_start_recv(handle, on_pcap_recv, NULL);

	/* send UDP demo */
	uint32_t dst_ip = 0;
	{
#ifdef _WIN32
		unsigned long netd = dst_ip_str ? inet_addr(dst_ip_str) : INADDR_NONE;
#else
		in_addr_t netd = dst_ip_str ? inet_addr(dst_ip_str) : INADDR_NONE;
#endif
		if (netd == INADDR_NONE) {
			dst_ip = (192<<24)|(168<<16)|(0<<8)|1;
		} else {
			dst_ip = ntohl(netd);
		}
	}
	const char* msg = "hello from simple stack";
	udp_send(dst_ip, 5001, 12345, (const uint8_t*)msg, strlen(msg));
	printf("Sent UDP to %s\n", dst_ip_str?dst_ip_str:"(default)");

	/* TCP demo (send SYN) */
	tcp_connect(dst_ip, 80, 40000);
	printf("Sent TCP SYN to %s:80\n", dst_ip_str?dst_ip_str:"(default)");

	/* 主循环：周期性调用 tick */
	for (int i=0;i<50;i++) {
#ifdef _WIN32
		Sleep(100);
#else
		usleep(100*1000);
#endif
		tcp_tick(100);
		arp_tick();
	}
	pcap_adapter_stop_recv(handle);
	pcap_adapter_close(handle);
	return 0;
}
